#ifndef xpack_test_docker_stack
#define xpack_test_docker_stack
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::test_docker_stack::inc
#include"test/helper.hpp" // 需要放第一
#include"define/nullref.hpp"
#include"docker/stack.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::test_docker_stack{
    xtest("stack") {
        using nlrd = inc::helper::nlrd_counter;

        auto used_bytes = inc::memory::used_bytes();
        {
            inc::stack<nlrd> sta;
            auto && top = sta->top();
            xassert_eq(top, inc::nullref);
            xassert_eq(sta->length, 0u);
            xassert_eq(sta->is_empty, true);

            uxx times = 0;
            sta.foreach([&](uxx i, nlrd & item){
                xassert_eq(item.value, i);
                times++;
            });

            xassert_eq(times, 0u);

            for(uxx i = 0; i < 128; i++){
                {
                    sta.push(nlrd{i});
                    xassert_nlrd(1, 0, 1, 1);
                }

                xassert_nlrd(0, 0, 0, 0);

                {
                    auto && top = sta->top();
                    xassert_ne(top, inc::nullref);
                    xassert_eq(top.value, i);
                    xassert_eq(sta->length, i + 1);
                    xassert_nlrd(0, 0, 0, 0);
                } // 退出作用域
                xassert_nlrd(0, 0, 0, 0);

                {
                    auto top = sta->top();
                    xassert_ne(top, inc::nullref);
                    xassert_eq(top.value, i);
                    xassert_eq(sta->length, i + 1);
                    xassert_nlrd(0, 1, 0, 0);
                } // 退出作用域
                xassert_nlrd(0, 0, 0, 1);

                times = 0;
                sta.foreach([&](uxx index, nlrd & item){
                    xassert_eq(item.value, sta->length - index - 1);
                    times++;
                });

                xassert_eq(times, i + 1);
            }

            xassert_eq(sta->is_empty, false);

            for(uxx i = sta->length; i--;){
                {
                    auto top = sta->top();
                    xassert_nlrd(0, 1, 0, 0);
                    auto && curr = sta.pop();
                    xassert_nlrd(0, 0, 1, 1);
                    xassert_ne(top, inc::nullref);
                    xassert_eq(curr->is_hold_value, true);
                    xassert_eq(top.value, i);
                    xassert_eq(curr->value().value, i);
                    xassert_eq(sta->length, i);
                    xassert_nlrd(0, 0, 0, 0);
                }
                xassert_nlrd(0, 0, 0, 2);

                times = 0;
                sta.foreach([&](uxx index, nlrd & item){
                    xassert_eq(item.value, sta->length - index - 1);
                    times++;
                });

                xassert_eq(times, i);
            }

            times = 0;
            sta.foreach([&](uxx i, nlrd & item){
                xassert_eq(item.value, i);
                times++;
            });

            xassert_eq(sta->is_empty, true);
            xassert_eq(times, 0u);
        }

        // 没有元素时 pop
        {
            inc::stack<nlrd> sta;
            auto empty = sta.pop();
            xassert_eq(empty->is_hold_value, false);
            xassert_eq(sta->length, 0u);
            xassert_nlrd(0, 0, 0, 0);
        }

        // 有一个元素时多次 pop 
        {
            inc::stack<nlrd> sta;
            sta.push(nlrd{1024});
            xassert_nlrd(1, 0, 1, 1);
            sta->top(nlrd{1024});
            xassert_nlrd(1, 0, 0, 1);
            xassert_alr(0, 1);
            sta.pop();
            xassert_nlrd(0, 0, 1, 2);

            auto empty = sta.pop();
            xassert_eq(empty->is_hold_value, false);
            xassert_eq(sta->is_empty, true);
            xassert_eq(sta->length, 0u);
            xassert_nlrd(0, 0, 0, 0);

            auto && top = sta->top();
            xassert_nlrd(0, 0, 0, 0);
            xassert_eq(top, inc::nullref);
            xassert_eq(sta->is_empty, true);
        }

        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 多值构造
        used_bytes = inc::memory::used_bytes();
        {
            inc::stack<nlrd> sta;
            sta.push(0, 1, 2);

            // 由于传的是 nlrd 构造时所需的参数，而不是 nlrd，所以不存在移动构造和析构
            xassert_nlrd(3, 0, 0, 0);
            xassert_alr(0, 0);

            sta.foreach([&](uxx index, nlrd & item){
                auto expect = sta->length - index - 1;
                xassert_eq(expect, item.value);
            });

            sta.push(3, 4, 5);

            sta.foreach([&](uxx index, nlrd & item){
                auto expect = sta->length - index - 1;
                xassert_eq(expect, item.value);
            });

            xassert_nlrd(3, 0, 0, 0);
            xassert_alr(0, 0);
        }
        xassert_nlrd(0, 0, 0, 6);
        xassert_eq(used_bytes, inc::memory::used_bytes());
    };
}

#endif
